package cn.zl.web.impl.virtualvideostream;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.yunbamboos.Const;
import cn.yunbamboos.exception.AppException;
import cn.yunbamboos.id.SnowflakeIdGenerator;
import cn.yunbamboos.mybatis.conditions.Conditions;
import cn.yunbamboos.rest.service.anno.RestServiceMapping;
import cn.yunbamboos.rest.service.dto.Page;
import cn.yunbamboos.rest.service.dto.out.BaseOutDTO;
import cn.yunbamboos.rest.service.transaction.Transaction;
import cn.zl.common.ZLConst;
import cn.zl.config.ZLConfig;
import cn.zl.mapper.VirtualVideoStreamMapper;
import cn.zl.model.VirtualVideoStream;
import cn.zl.web.dto.virtualvideostream.AddVirtualVideoStreamInDTO;
import cn.zl.web.dto.virtualvideostream.AddVirtualVideoStreamOutDTO;
import cn.zl.web.dto.virtualvideostream.DeleteVirtualVideoStreamInDTO;
import cn.zl.web.dto.virtualvideostream.DeleteVirtualVideoStreamOutDTO;
import cn.zl.web.dto.virtualvideostream.PlayVirtualVideoStreamInDTO;
import cn.zl.web.dto.virtualvideostream.PlayVirtualVideoStreamOutDTO;
import cn.zl.web.dto.virtualvideostream.QueryVirtualVideoStreamByPageInDTO;
import cn.zl.web.dto.virtualvideostream.QueryVirtualVideoStreamByPageOutDTO;
import cn.zl.web.inter.virtualvideostream.IVirtualVideoStreamService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.net.URI;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Service("VirtualVideoStreamServiceImpl")
public class VirtualVideoStreamServiceImpl implements IVirtualVideoStreamService {

    private static final Logger logger = LoggerFactory.getLogger(VirtualVideoStreamServiceImpl.class);

    @Resource
    private VirtualVideoStreamMapper virtualVideoStreamMapper;
    @Resource
    private SnowflakeIdGenerator snowflakeIdGenerator;
    @Resource
    private ZLConfig zlConfig;

    @RestServiceMapping(url = "/web/virtual-video-stream/queryByPage", name = "条件分页查询模拟视频流列表服务", in = QueryVirtualVideoStreamByPageInDTO.class, out = QueryVirtualVideoStreamByPageOutDTO.class)
    @Override
    public BaseOutDTO queryByPage(QueryVirtualVideoStreamByPageInDTO in) {
        // 创建分页对象
        Page<VirtualVideoStream> page = new Page<>(in.getPageNo(), in.getPageSize());
        // 添加动态条件
        Conditions where = new Conditions();
        // 查询总数
        int total = virtualVideoStreamMapper.countForPage(page, where);
        // 查询当前页码数据
        List<VirtualVideoStream> list = virtualVideoStreamMapper.queryForPage(page, where);
        page.setRows(list).setTotal(total);
        return new QueryVirtualVideoStreamByPageOutDTO(page);
    }

    @RestServiceMapping(url = "/web/virtual-video-stream/add", name = "添加新模拟视频流服务", in = AddVirtualVideoStreamInDTO.class, out = AddVirtualVideoStreamOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO add(AddVirtualVideoStreamInDTO in) {
        if (in.getFileSize() != 1) {
            throw AppException.c("只能上传一个文件");
        }
        String fileId = snowflakeIdGenerator.nextIdStr();
        VirtualVideoStream stream = new VirtualVideoStream();
        stream.setFileId(fileId);
        stream.setApp(in.getApp());
        stream.setStream(in.getStream());
        stream.setCreateTime(LocalDateTimeUtil.format(LocalDateTime.now(), DatePattern.NORM_DATETIME_PATTERN));
        // 写文件
        Map<String, MultipartFile> files = in.getFiles();

        for (Map.Entry<String, MultipartFile> entry : files.entrySet()) {
            MultipartFile file = entry.getValue();
            try {
                String name = file.getOriginalFilename();
                if (StrUtil.isBlank(name)) {
                    throw AppException.c("文件名为空");
                }
                String type = name.substring(name.lastIndexOf(".") + 1);
                if ("mp4".equals(type) || "avi".equals(type)) {
                    stream.setFileType(type);
                    FileUtil.writeBytes(file.getBytes(), ZLConst.VIRTUAL_VIDEO.DIR + fileId + "." + type);
                } else {
                    throw AppException.c("{}文件类型不支持", type);
                }
            } catch (Exception e) {
                logger.error("write bytes error", e);
            }
        }

        if (StrUtil.isBlank(stream.getFileType())) {
            throw AppException.c("未知文件类型");
        }
        virtualVideoStreamMapper.insert(stream);
        return new AddVirtualVideoStreamOutDTO();
    }

    @RestServiceMapping(url = "/web/virtual-video-stream/delete", name = "删除模拟视频流服务", in = DeleteVirtualVideoStreamInDTO.class, out = DeleteVirtualVideoStreamOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO delete(DeleteVirtualVideoStreamInDTO in) {
        in.forEach(fileId -> {
            Optional<VirtualVideoStream> optional = virtualVideoStreamMapper.queryByPrimaryKey(fileId);
            if (optional.isPresent()) {
                VirtualVideoStream stream = optional.get();
                virtualVideoStreamMapper.deleteByPrimaryKey(fileId);
                FileUtil.del(ZLConst.VIRTUAL_VIDEO.DIR + fileId + "." + stream.getFileType());
            }
        });
        return new DeleteVirtualVideoStreamOutDTO();
    }

    @RestServiceMapping(url = "/web/virtual-video-stream/play-stream", name = "播放模拟视频流服务", in = PlayVirtualVideoStreamInDTO.class, out = PlayVirtualVideoStreamOutDTO.class, transaction = Transaction.WRITE)
    @Override
    public BaseOutDTO playStream(PlayVirtualVideoStreamInDTO in) {
        String realUrl = in.getSession("real_url");
        URI url = URI.create(realUrl);
        String host = url.getHost();
        PlayVirtualVideoStreamOutDTO out = new PlayVirtualVideoStreamOutDTO();
        String fileId = in.getFileId();
        Optional<VirtualVideoStream> optional = virtualVideoStreamMapper.queryByPrimaryKey(fileId);
        optional.ifPresent(stream -> {
            out.setHost(host);
            out.setApp(stream.getApp());
            out.setStream(stream.getStream());
            out.setConfig(zlConfig);
        });
        return out;
    }

}
